package controllers

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dchest/captcha"
	"io/ioutil"
	"log"
	"micro-bbs/datamodels"
	"micro-bbs/initialize"
	"micro-bbs/libs"
	"micro-bbs/services"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"time"
)

type UserController struct {

	UserService services.UserInterfaceService
}

func NewUserController() *UserController {
	obj := &UserController{
		UserService: services.NewUserService(),
	}
	return obj
}


//获取用户详情页
func (this *UserController) Detail(c *gin.Context){
	idStr := c.Param("id")
	id, _ := strconv.Atoi(idStr)
	initialize.IrisLog.Infof("[用户控制器-http请求数据]-[%d]", id)

	user,err := this.UserService.GetUserInfoById(int64(id))
	fmt.Println("user:",user)
	if err != nil || user == nil {
		fmt.Println("rpc request failed:", err)
		c.HTML(http.StatusNotFound, "error/404.html", gin.H{"title": "404"})
		return
	}

	//result, err := this.UserService.GetUserInfo(int64(id))
	//initialize.IrisLog.Infof("[用户控制器-userInfo返回数据]-[%s]", libs.StructToJson(result))
	//if err != nil {
	//	c.HTML(http.StatusNotFound, "error/404.html", gin.H{"title": "404"})
	//	return
	//}

	//获取发布的帖子
	var query datamodels.PostByQuery
	uid := int64(id)
	query.UserId = &uid
	query.Limit = 10
	postList, _ := this.UserService.GetPostByQuery(query)
	initialize.IrisLog.Infof("[用户控制器-postList返回数据]-[%s]", postList)

	//获取发布的评论
	//var query datamodels.ParamsPostCommentList
	//query.PostId = id
	//commentList, _ := this.PostService.GetPostCommentList(query)
	//initialize.IrisLog.Infof("[帖子控制器-commentList返回数据]-[%s]", libs.StructToJson(commentList))

	c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{
		"title": user.(map[string]interface{})["nickname"],
		"address": "bbs.100txy.com",
		"id": id,
		"user": user,
		"postData": postList,
	}))
}

//获取登录用户信息
func (this *UserController) LoginInfo(c *gin.Context){
	//用户信息
	var userinfo interface{}
	//获取恭喜session
	sessionStr,err := initialize.RedisClient.Get("sso_client_login").Result()
	if err != nil || len(sessionStr) == 0{
		//panic(err)
		c.JSON(http.StatusOK, libs.ReturnJson(5004,"", gin.H{
			"userinfo": userinfo,
		}))
		return
	}
	//if len(respBytes) == 0{
	//	return nil
	//}
	tokenMap := make(map[string]interface{})
	err = json.Unmarshal([]byte(sessionStr), &tokenMap)
	if err != nil {
		fmt.Println("Umarshal failed:", err)
		fmt.Println("sessionStr:",sessionStr)
		return
	}

	//效验token
	res,err := this.checkToken(c,tokenMap["access_token"].(string))
	fmt.Printf("res:%T",res)
	if res.(map[string]interface{})["user_id"] != ""  && err == nil {
		uid, _ := strconv.ParseInt(res.(map[string]interface{})["user_id"].(string), 10, 64)
		bbsUserInfo := initialize.RedisClient.Get("member:userinfo:"+strconv.FormatInt(uid,10))
		if bbsUserInfo.Val() != ""{
			userinfoMap := make(map[string]interface{})
			err = json.Unmarshal([]byte(bbsUserInfo.Val()), &userinfoMap)
			if err != nil {
				fmt.Println("Umarshal failed:", err)
				return
			}
			//推送登录日志MQ消息
			services.NewRabbitmqService().PushLoginLog(uid)
			c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{
				"tokenMap": tokenMap,
				"res": res,
				"userinfo": userinfoMap,
			}))
			//同步用户信息
			var oauth_user datamodels.BbsUser
			oauth_user.ID = int64(userinfoMap["id"].(float64))
			oauth_user.HeadImg = userinfoMap["head_img"].(string)
			oauth_user.IsAdmin = int(userinfoMap["is_admin"].(float64))
			oauth_user.IsVip = int(userinfoMap["is_vip"].(float64))
			oauth_user.Nickname = userinfoMap["nickname"].(string)
			oauth_user.Pass = userinfoMap["password"].(string)
			oauth_user.Reward = int64(userinfoMap["reward"].(float64))
			oauth_user.Status = int(userinfoMap["status"].(float64))
			oauth_user.Uid = userinfoMap["uid"].(string)
			_,err = this.UserService.SyncUser(oauth_user)
			if err != nil {
				return
			}
			return
		}
		user,err := this.UserService.GetUserInfoById(uid)
		fmt.Println("user:",user)
		if err != nil || user == nil {
			fmt.Println("rpc request failed:", err)
			return
		}
		//同步用户信息
		var oauth_user datamodels.BbsUser
		oauth_user.ID = user.(map[string]interface{})["id"].(int64)
		oauth_user.HeadImg = user.(map[string]interface{})["head_img"].(string)
		oauth_user.IsAdmin = user.(map[string]interface{})["is_admin"].(int)
		oauth_user.IsVip = user.(map[string]interface{})["is_vip"].(int)
		oauth_user.Nickname = user.(map[string]interface{})["nickname"].(string)
		oauth_user.Pass = user.(map[string]interface{})["password"].(string)
		oauth_user.Reward = user.(map[string]interface{})["reward"].(int64)
		oauth_user.Status = user.(map[string]interface{})["status"].(int)
		oauth_user.Uid = user.(map[string]interface{})["uid"].(string)
		_,err = this.UserService.SyncUser(oauth_user)
		if err != nil {
			return
		}

		//缓存
		redisUser, _ := json.Marshal(user)
		initialize.RedisClient.Set("member:userinfo:"+strconv.FormatInt(uid,10),redisUser,-1)
		userinfo = user
	}

	//推送登录日志MQ消息
	userId, _ := strconv.ParseInt(userinfo.(map[string]interface{})["id"].(string), 10, 64)
	services.NewRabbitmqService().PushLoginLog(userId)
	c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{
		"tokenMap": tokenMap,
		"res": res,
		"userinfo": userinfo,
	}))
}

//效验sso分发的access_token有效性
func (this *UserController)checkToken(c *gin.Context, oauth_token string) (interface{},error) {
	req, err := http.NewRequest(http.MethodGet, "http://ssoserver.com:9096/test", nil)
	req.Header.Set("Content-Type","application/x-www-form-urlencoded")
	req.Header.Set("Authorization","Bearer "+oauth_token)
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	defer resp.Body.Close()
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	fmt.Println("resp str:",string(bs))//invalid access token
	if string(bs) == "invalid access token" {
		return "", errors.New("invalid access token")
	}
	m := make(map[string]interface{})
	err = json.Unmarshal(bs, &m)
	if err != nil {
		return "", err
	}
	fmt.Println("map:", m)
	return m, nil
}

//退出sso
func (this *UserController)Logout(c *gin.Context) {
	//清除redis共享session
	initialize.RedisClient.Del("sso_client_login")
	req, err := http.NewRequest(http.MethodGet, "http://ssoserver.com:9096/logout?redirect_uri=http%3a%2f%2fssoserver.com%3a9096%2fauthorize%3fclient_id%3dtest_client_3%26response_type%3dcode%26scope%3dall%26state%3dxyz%26", nil)
	req.Header.Set("Content-Type","application/x-www-form-urlencoded")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	//defer resp.Body.Close()
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)

	}
	fmt.Println("resp str:",string(bs))//invalid access token
	m := make(map[string]interface{})
	err = json.Unmarshal(bs, &m)
	if err != nil {
	}
	fmt.Println("map:", m)
	c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{}))
}

//注册用户信息
func (this *UserController) Register(c *gin.Context){
	//绑定参数
	type Query struct {
		Email       string  `json:"email" binding:"required"`       //邮箱
		Vercode     int     `json:"vercode" binding:"required"`     //邮箱验证码
		Username    string  `json:"username" binding:"required"`    //昵称
		Pass        string  `json:"pass" binding:"required"`      	//密码
		Repass      string  `json:"repass" binding:"required"`      //重复密码
		CaptchaId   string  `json:"captcha_id" binding:"required"`  //验证码ID
		ImgCode     string  `json:"img_code" binding:"required"`     //图形验证码
	}
	var query Query

	if err := c.ShouldBind(&query); err != nil {
		log.Println("Controller:Register", "用户注册检测参数",err.Error())
		c.JSON(http.StatusOK, libs.ReturnJson(4000, "", nil))
		return
	}
	//检查验证码
	verifyVal := captcha.VerifyString(query.CaptchaId, query.ImgCode)
	if !verifyVal {
		c.JSON(http.StatusOK, libs.ReturnJson(4005,"", gin.H{}))
		return
	}
	//效验邮箱验证码
	email_code,err := initialize.RedisClient.Get("reg_email_"+query.Email).Result()
	if err != nil || len(email_code) == 0{
		//panic(err)
		c.JSON(http.StatusOK, libs.ReturnJson(5006,"", gin.H{}))
		return
	}
	//rpc请求注册用户
	var regUser datamodels.ProtoRegisterReq
	regUser.Email = query.Email
	regUser.Nickname = query.Username
	regUser.Password = query.Pass
	resBool,err := this.UserService.Register(regUser)
	if err != nil || resBool == false {
		//logrus.Errorf("[rpc request failed]-[%s]", err)
		initialize.IrisLog.Errorf("[rpc request failed]-[%s]", err)
		return
	}

	c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{
		"success": resBool,
	}))
}

//用户签到
func (this *UserController) SignIn(c *gin.Context){
	//从解析token中间件获取用户ID
	uid, ok := c.Get("jwtUserId")  //取值 实现了跨中间件取值
	if !ok{
		c.JSON(http.StatusOK, libs.ReturnJson(5002,"", gin.H{}))
	}
	fmt.Printf("uid%T\n",uid)
	//判断是否已签到
	val,_ := initialize.RedisClient.SIsMember("member:signin:set:"+time.Now().Format("2006-01-02"),uid).Result()
	fmt.Printf("val%T\n",val)
	fmt.Println("val:",val)
	if val == true {
		c.JSON(http.StatusOK, libs.ReturnJson(5007,"", gin.H{}))//已签到
		return
	}

	type SignInfo struct {
		Days        int     `json:"days"`        //连续签到天数
		SignDate    string  `json:"sign_date"`   //上次签到日期
		Reward      int     `json:"reward"`      //上次签到飞吻
	}
	var signInfo SignInfo
	redisSignInfo,_ := initialize.RedisClient.Get("member:signin:"+strconv.FormatInt(uid.(int64),10)).Result()
	if len(redisSignInfo) > 0 {
		fmt.Printf("redisSignInfo%T\n",redisSignInfo)
		fmt.Println("redisSignInfo:",redisSignInfo)
		json.Unmarshal([]byte(redisSignInfo), &signInfo)
		signInfo.Days = signInfo.Days + 1
	}else{
		signInfo.Days = 1
	}
	signInfo.SignDate = time.Now().Format("2006-01-02")
	//连续5天签到每天加10,其他每天加5
	var size int
	if signInfo.Days >= 5 {
		size = 10
	}else{
		size = 5
	}
	signInfo.Reward = size

	//根据uid获取用户信息
	user,err := services.NewUserService().GetUserInfoById(uid.(int64))
	initialize.IrisLog.Infof("user:",user)
	if err != nil || user == nil {
		initialize.IrisLog.Errorf("rpc request SignIn failed:", err)
		return
	}
	//更新用户数据，组装请求数据
	//{{rpc更新用户奖励
	var protoUser datamodels.ProtoUser
	protoUser.Id = uid.(int64)
	var rewardRes int64
	reward, ok := user.(map[string]interface{})["reward"]
	if ok {
		rewardRes = int64(reward.(float64))
	} else {
		rewardRes = 0
	}
	protoUser.Reward = rewardRes + int64(size)
	var protoUserReq datamodels.ProtoUserReq
	protoUserReq.User = protoUser
	protoUserReq.Number = int64(size)
	protoUserReq.Typo = "signin"
	//点一次执行扣减操作
	recordId,err := services.NewUserService().UpdateUser(protoUserReq)
	if recordId == 0 || err != nil{
		c.JSON(http.StatusOK, libs.ReturnJson(5105,"", gin.H{}))
		return
	}
	//添加连续签到记录
	signInfoJson, _ := json.Marshal(signInfo)
	initialize.RedisClient.Set("member:signin:"+strconv.FormatInt(uid.(int64),10),signInfoJson,-1)
	//添加今日签到记录
	initialize.RedisClient.SAdd("member:signin:set:"+time.Now().Format("2006-01-02"),uid)
	c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{
		"success": true,
		"recordId": recordId,
	}))
	return
}

//用户签到信息
func (this *UserController) SignInfo(c *gin.Context){
	//从解析token中间件获取用户ID
	uid, ok := c.Get("jwtUserId")  //取值 实现了跨中间件取值
	if !ok{
		c.JSON(http.StatusOK, libs.ReturnJson(5002,"", gin.H{}))
	}
	var is_sign bool
	//判断是否已签到
	val,_ := initialize.RedisClient.SIsMember("member:signin:set:"+time.Now().Format("2006-01-02"),uid).Result()
	if val == true {
		is_sign = true
	}else{
		is_sign = false
	}

	type SignInfo struct {
		Days        int     `json:"days"`        //连续签到天数
		SignDate    string  `json:"sign_date"`   //上次签到日期
		Reward      int     `json:"reward"`      //上次签到飞吻
	}
	var signInfo SignInfo
	redisSignInfo,_ := initialize.RedisClient.Get("member:signin:"+strconv.FormatInt(uid.(int64),10)).Result()
	if len(redisSignInfo) > 0 {
		json.Unmarshal([]byte(redisSignInfo), &signInfo)

	}
	c.JSON(http.StatusOK, libs.ReturnJson(200,"", gin.H{
		"is_sign": is_sign,
		"signInfo": signInfo,
	}))
	return
}